﻿using System;
using System.Diagnostics;
using System.ServiceModel;
using Bookvar.ApplicationModel;
using Bookvar.ObjectModel;
using Bookvar.ObjectModel.Actions.Collaboration;

namespace Bookvar.Collaboration.ServerSide
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    //, ConcurrencyMode = ConcurrencyMode.Multiple)]
    internal class CollaborationService : ICollaborationService
    {
        //private static readonly Object syncObj = new Object();
        public static MindMap MindMap;

        private readonly ICollaborationUsersManager collaborationUsersManager;

        private ICollaborationServiceCallback callback;
        private CollaborationUser client;

        private static IExecutionContext mapPanel;

        public CollaborationService()
        {
            collaborationUsersManager = BookvarApplication.Current.ServiceLayer.GetService<ICollaborationUsersManager>();
            
            if(collaborationUsersManager == null)
            {
                throw new CollaborationException("ICollaboraionUsersManager was not found in the service layer.");
            }
        }

        public UserJoinResponse Join(string name)
        {
            // hack just for now. 
            // todo: implement logic for checking if name is free.
            if(collaborationUsersManager.IsUserNameFree(name) == false)
            {
                return Join(name + "`");
            }

            client = collaborationUsersManager.GenerateNewUser(name);
            callback = OperationContext.Current.GetCallbackChannel<ICollaborationServiceCallback>();
            collaborationUsersManager.AddUser(client, callback);

            collaborationUsersManager.InformUserJoined(client);

            CollaborationUser[] users = new CollaborationUser[collaborationUsersManager.CollaborationUsers.Count];
            collaborationUsersManager.CollaborationUsers.CopyTo(users, 0);
            
            UserJoinResponse response = new UserJoinResponse();
            response.CurrentUser = client;
            response.Users = users;

            return response;
        }

        public void ProcessAction(ActionBase action)
        {
            // TODO: validate action

            Debug.Assert(client != null);
            if (client == null)
            {
                throw new InvalidOperationException("Internal Error. Client must not be null");
            }

            action.PublisherGuid = client.ID;

            SayAction sayAction = action as SayAction;
            if (sayAction != null)
            {
                sayAction.CollaborationEventsPublisher =
                    BookvarApplication.Current.ServiceLayer.GetService<ICollaborationEventsPublisher>();
            }

            action.Execute(mapPanel);
            collaborationUsersManager.InformProcessAction(action);
        }

        public MindMap GetMindmap()
        {
            return MindMap;
        }

        public static void SetExecutionContext(IExecutionContext mindMap)
        {
            mapPanel = mindMap;
        }

        public void Leave()
        {
            collaborationUsersManager.UserLeaves(client);
        }
    }
}